﻿/********************************************************************************
* Copyright 2010 Zane Thorn (zane.thorn@gmail.com)                              *
*                                                                               *
* NeturalMath is free software: you can redistribute it and/or modify           *
* it under the terms of the GNU Lesser General Public License as published by   *
* the Free Software Foundation, either version 3 of the License, or             *
* (at your option) any later version.                                           *
*                                                                               *
* NeturalMath is distributed in the hope that it will be useful,                *
* but WITHOUT ANY WARRANTY; without even the implied warranty of                *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
* GNU Lesser General Public License for more details.                           *
*                                                                               *
* You should have received a copy of the GNU Lesser General Public License      *
* along with NeturalMath.  If not, see <http://www.gnu.org/licenses/>.          *
********************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using NeturalMath.Expressions;

namespace NeturalMath
{
    ///// <summary>
    ///// Delegate used internally to point to a system function
    ///// </summary>
    ///// <param name="parameters"></param>
    ///// <returns></returns>
    //public delegate MathValue MathFunction(params MathValue[] parameters);

    /// <summary>
    /// Represents a function definition used by NeturalMath
    /// </summary>
    public sealed class Function:BlockSymbol
    {
        #region Constructors

        internal Function(string name,BlockSymbol parentDomain,MathRuntime runtime,DomainExpression value,Scope scope)
            :base(name,parentDomain,runtime,value,scope)
        {
            if (value == null)
                throw new ArgumentNullException("value");
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets the set of parameter definitions for the function
        /// </summary>
        public FunctionParameter[] Parameters { get; private set; }

        #endregion

        #region Public Methods

        public MathValue Invoke(IEnumerable<MathValue> values)
        {
            var valueArray = values.ToArray();

            for (int i = 0; i < Parameters.Length; i++)
            {
                if (i >= valueArray.Length)
                {
                    SafeSetVariable(Parameters[i].Name, Parameters[i].Value);
                    continue;
                }

                var val = valueArray[i];
                var param = Parameters[i];
                if (val != null)
                    SafeSetVariable(param.Name, new ConstantValueExpression(val,Runtime));
                else
                    SafeSetVariable(param.Name, param.Value);
            }
            return Invoke();
        }

        #endregion

        #region Helper Methods

        internal void SetParameters(IEnumerable<FunctionParameter> parameters)
        {
            Parameters = parameters.ToArray();
            foreach (var p in Parameters)
                SafeSetVariable(p.Name, p.Value);
        }

        #endregion
    }
}
